package com.gitee.wsl.common.svg.filter

import com.gitee.wsl.common.svg.attributes.AttributeProperty
import com.gitee.wsl.common.svg.attributes.DefaultAttributeProperty
import com.gitee.wsl.common.svg.attributes.FloatAttributeProperty
import com.gitee.wsl.common.svg.attributes.HasAttributes
import com.gitee.wsl.common.svg.attributes.HasAttributesImpl
import com.gitee.wsl.common.svg.attributes.HasDimensions
import com.gitee.wsl.common.svg.attributes.HasDimensionsImpl
import com.gitee.wsl.common.svg.attributes.HasOrigin
import com.gitee.wsl.common.svg.attributes.HasOriginImpl
import com.gitee.wsl.common.svg.elements.Element
import com.gitee.wsl.common.svg.clip.PosMode

class Filter(validation: Boolean = false, hasAttributes: HasAttributes = HasAttributesImpl(validation)) :
    Element("filter", validation,hasAttributes),
    HasOrigin by HasOriginImpl(hasAttributes),
    HasDimensions by HasDimensionsImpl(hasAttributes)
{
    var filterUnits: PosMode? by DefaultAttributeProperty()

    init {
        filterUnits = PosMode.MODE_BOX
    }

    fun gaussianBlur(stdDeviationX:Float,stdDeviationY:Float=0f){
        add(GaussianBlur(validation)){
            stdDeviation="$stdDeviationX,$stdDeviationY"
        }
    }

    fun offset(dx:Float,dy:Float){
        add(Offset(validation)){
            this.dx=dx
            this.dy=dy
        }
    }

    fun color(block:Color.()->Unit){
        add(Color(validation),block)
    }

    fun convolveMatrix(block:ConvolveMatrix.()->Unit) {
        add(ConvolveMatrix(validation), block)
    }

    fun composite(block:Composite.()->Unit){
        add(Composite(validation),block)
    }
}

open class BaseFilterItem(name:String, validation: Boolean = false, hasAttributes: HasAttributes = HasAttributesImpl(validation)):
    Element("feGaussianBlur", validation,hasAttributes){

    }

class GaussianBlur(validation: Boolean = false): BaseFilterItem("feGaussianBlur", validation){
    var stdDeviation:String? by AttributeProperty()
}

class Offset(validation: Boolean = false): BaseFilterItem("feOffset", validation){
      var dx:Float? by FloatAttributeProperty()
      var dy:Float? by FloatAttributeProperty()
}

class Color(validation: Boolean = false): BaseFilterItem("feColorMatrix", validation){

    var type:ColorFilterType? by DefaultAttributeProperty()

    private var value:String?  by AttributeProperty()

    fun colorMatrix(vararg colorValue:Float){
        value=colorValue.joinToString(" ")
    }
}

enum class ColorFilterType(val value:String) {
    TYPE_MATRIX ("matrix"),
    TYPE_SATURATE ("saturate"),
    TYPE_HUEROTATE  ("hueRotate"),
    TYPE_LUMINANCETOALPHA("luminanceToAlpha");

    override fun toString(): String {
        return value
    }
}

class ConvolveMatrix(validation: Boolean = false): BaseFilterItem("feConvolveMatrix", validation){
    /**
     * The kernel size
     * default size is 3
     */
     var order :Float? by FloatAttributeProperty()

    /**
     * Convolve filter
     */
     var kernelMatrix: String? by AttributeProperty()

    fun kernelMatrix(vararg matrix:Float){
        kernelMatrix=matrix.joinToString(" ")
    }

    /**
     * The matrix sum
     * default is sum of kernelMatrix
     */
     var divisor :Float? by FloatAttributeProperty()

    /**
     * Bias value
     */
     var bias :Float? by FloatAttributeProperty()

    /**
     * The centerX bias of target
     */
     var targetX :Float? by FloatAttributeProperty()

    /**
     * The centerY bias of target
     */
     var targetY :Float? by FloatAttributeProperty()

    /**
     * Edge mode
     * Convolution boundary position repetition pattern
     *
     * @see EdgeMode
     */
     var edgeMode: EdgeMode? by DefaultAttributeProperty()

    /**
     * The kernel unit of X-axis
     */
     var kernelUnitLengthX :Float? by FloatAttributeProperty()

    /**
     * The kernel unis of Y-axis
     */
     var kernelUnitLengthY :Float? by DefaultAttributeProperty()

    /**
     * Need calc contains alpha
     * false contains alpha
     */
     var preserveAlpha :Boolean? by DefaultAttributeProperty()


}

enum class  EdgeMode (val value:String) {
    EDGE_MODE_DUPLICATE("duplicate"),
    EDGE_MODE_WRAP ("wrap"),
    EDGE_MODE_NONE ( "none");
    override fun toString(): String {
        return value
    }
}

class Composite(validation: Boolean = false): BaseFilterItem("feColorMatrix", validation){

    /**
     * The second input
     */
     var in2: String? by AttributeProperty()

    /**
     * The operate to point combines certain rule
     *
     * @see OperateType
     */
     var operate:OperateType? by DefaultAttributeProperty()

    /**
     * only use when operate is arithmetic
     *
     * @see OperateType.OPERATE_ARITHMETIC
     */
    protected var k1 :Float? by FloatAttributeProperty()

    /**
     * only use when operate is arithmetic
     *
     * @see OperateType.OPERATE_ARITHMETIC
     */
    protected var k2 :Float? by FloatAttributeProperty()

    /**
     * only use when operate is arithmetic
     *
     * @see OperateType.OPERATE_ARITHMETIC
     */
    protected var k3 :Float? by FloatAttributeProperty()

    /**
     * only use when operate is arithmetic
     *
     * @see OperateType.OPERATE_ARITHMETIC
     */
    protected var k4 :Float? by FloatAttributeProperty()

    fun arithmetic(k1 :Float,k2 :Float,k3 :Float,k4 :Float,){
        operate = OperateType.OPERATE_ARITHMETIC
        this.k1=k1
        this.k2=k2
        this.k3=k3
        this.k4=k4
    }
}

enum class OperateType(val value:String) {
     OPERATE_OVER ("over"),
     OPERATE_IN ( "in"),
     OPERATE_ATOP ( "atop"),
     OPERATE_OUT ( "out"),
     OPERATE_XOR ("xor"),
     OPERATE_LIGHTER ( "lighter"),

    /**
     * When operate is arithmetic,it will use the rule to generate result
     * result = k1*i1*i2 + k2*i1 + k3*i2 + k4
     */
     OPERATE_ARITHMETIC ( "arithmetic");

    override fun toString(): String {
        return value
    }
}